package com.gxd.business.bind.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.gxd.business.bind.IFieldBind;
import com.gxd.business.bind.aop.FieldBind;
import com.gxd.business.bind.enums.BindType;
import com.gxd.common.core.domain.entity.SysDept;
import com.gxd.common.core.domain.entity.SysDictData;
import com.gxd.common.core.domain.entity.SysUser;
import com.gxd.common.core.redis.RedisCache;
import com.gxd.system.service.ISysDeptService;
import com.gxd.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 字段绑定工具类 - 支持多种类型的字段自动绑定：
 * DICT（字典）、DEPT（部门）、USER（用户）、自定义缓存等
 */
@Component
@Slf4j
@SuppressWarnings("all")
public class SsFieldBind implements IFieldBind {

    // 缓存键分隔符
    private static final String CACHE_SPLIT = ":";

    // 系统字典缓存前缀
    private static final String SYS_DICT_PREFIX = "sys_dict:";

    private final RedisCache redisCache;

    public SsFieldBind(RedisCache redisCache) {
        this.redisCache = redisCache;
    }

    /**
     * 设置绑定字段的目标值
     * @param fieldBind 字段绑定注解信息
     * @param fieldValue 当前字段的原始值
     * @param metaObject MyBatis MetaObject 对象，用于设置目标字段值
     */
    @Override
    public void setMetaObject(FieldBind fieldBind, Object fieldValue, MetaObject metaObject) {
        try {
            if (ObjectUtil.isEmpty(fieldValue)) return;

            String[] array;
            Object targetType;

            // 统一将 fieldValue 转换为字符串数组
            if (fieldValue instanceof Integer) {
                array = new String[]{fieldValue.toString()};
                targetType = "";
            }else if (fieldValue instanceof String) {
                array = ((String) fieldValue).split(",");
                targetType = "";
            } else if (fieldValue instanceof JSONArray) {
                array = ((JSONArray) fieldValue).toArray(new String[0]);
                targetType = new JSONArray();
            } else if (fieldValue instanceof String[]) {
                array = (String[]) fieldValue;
                targetType = new String[0];
            } else {
                return;
            }

            // 执行绑定值解析
            Map<String, Object> resolved = resolveBinding(fieldBind, array, targetType);

            // 将解析出的值设置到目标字段中
            resolved.forEach((k, v) -> {
                if (k.contains(":")) {
                    metaObject.setValue(k.split(":")[1], v);
                } else {
                    metaObject.setValue(k, v);
                }
            });

        } catch (Exception e) {
            log.error("字段绑定失败 - field: {}, value: {}, error: {}", fieldBind, fieldValue, e.getMessage(), e);
        }
    }

    /**
     * 解析绑定结果为 Map（键为目标字段，值为解析后的值）
     * @param fieldBind 字段绑定注解信息
     * @param fieldValue 当前字段的原始值
     * @param targetType
     * @return
     */
    private Map<String, Object> resolveBinding(FieldBind fieldBind, String[] fieldValue, Object targetType) {
        Map<String, Object> targetMap = new HashMap<>();
        List<JSONObject> resolvedList = new ArrayList<>();

        // 每一个原始值进行一次绑定解析
        for (String val : fieldValue) {
            resolvedList.add(resolveSingle(fieldBind, val));
        }

        // 遍历目标字段，填充最终结果
        for (String target : fieldBind.target()) {
            //目标待绑定属性
            String targetField = target.contains(":") ? target.split(":")[0] : "";
            Object bindResult = extractTargetValue(fieldBind, targetField, resolvedList, targetType);

            if (fieldBind.bindEmpty() || (bindResult != null && StrUtil.isNotEmpty(bindResult.toString()))) {
                targetMap.put(target, bindResult);
            }
        }

        return targetMap;
    }

    /**
     * 解析单个绑定值（根据绑定类型选择处理逻辑）
     */
    private JSONObject resolveSingle(FieldBind fieldBind, String value) {
        switch (fieldBind.type()) {
            case DICT_WEBAPP:
                return resolveDict(SYS_DICT_PREFIX + fieldBind.key(), value);
            case DICT_TREE:
                return resolveDictTree(fieldBind.type().getCode() + fieldBind.key(), value); //BindType.DICT_TREE.getCode() +
            case DEPT_CODE:
                return resolveDept(value);
            case USER:
                return resolveUser(value);
            default:
                if (fieldBind.customType()) {
                    return resolveCustom(fieldBind.key(), value);
                }
                return new JSONObject();
        }
    }

    /**
     * 提取最终绑定结果（根据目标字段 key 提取解析列表中的值）
     */
    private Object extractTargetValue(FieldBind fieldBind, String targetField, List<JSONObject> jsonList, Object targetType) {

        //如果字段名为空 则获取绑定类型对应的默认字段名
        if (StrUtil.isBlank(targetField)) {
            targetField = getDefaultKey(fieldBind.type());
        }

        if (StrUtil.isBlank(targetField)) return null; //字段名如果还是为空 不翻译

        List<String> values = new ArrayList<>();
        for (JSONObject json : jsonList) {
            values.add(Optional.ofNullable(json.getString(targetField)).orElse(""));
        }

        // 根据目标类型返回不同结构的值
        if (targetType instanceof String) {
            return joinIfValid(values, fieldBind.bindEmpty());
        } else if (targetType instanceof String[]) {
            return values.toArray(new String[0]);
        } else if (targetType instanceof JSONArray) {
            return JSONUtil.parseArray(values);
        }

        return null;
    }

    /**
     * 拼接多个值为字符串（如果允许为空或有有效内容）
     */
    private String joinIfValid(List<String> values, boolean allowEmpty) {
        if (!allowEmpty && values.size() == 1 && StrUtil.isEmpty(values.get(0))) {
            return null;
        }
        return String.join(StringPool.COMMA, values);
    }

    /**
     * 获取绑定类型的默认字段 key
     */
    private String getDefaultKey(BindType type) {
        switch (type) {
            case DICT_WEBAPP:
                return "dictLabel";
            case DICT_TREE:
                return "mc";
            case DEPT_CODE:
                return "name";
            case USER:
                return "nickname";
            default:
                return "";
        }
    }

    /**
     * 自定义类型绑定解析（从 Redis 获取值并转为 JSON）
     */
    private JSONObject resolveCustom(String key, String value) {
        Object raw = redisCache.getCacheObject(key + value);
        return BeanUtil.toBean(raw, JSONObject.class);
    }

    /**
     * 普通字典绑定解析
     */
    private JSONObject resolveDict(String dictKey, String dictValue) {
        Object raw = redisCache.getCacheObject(dictKey);
        if (raw == null) return new JSONObject();

        List<SysDictData> dictList = JSONUtil.toList(JSONUtil.parseArray(raw.toString()), SysDictData.class);
        return dictList.stream()
                .filter(d -> dictValue.equals(d.getDictValue()))
                .findFirst()
                .map(d -> BeanUtil.toBean(d, JSONObject.class))
                .orElse(new JSONObject());
    }

    /**
     * 树形字典绑定解析
     */
    private JSONObject resolveDictTree(String dictKey, String value) {
        Object raw = redisCache.getCacheObject(dictKey + CACHE_SPLIT + value);
        return BeanUtil.toBean(raw, JSONObject.class);
    }

    /**
     * 部门绑定解析
     */
    private JSONObject resolveDept(String value) {
        ISysDeptService deptService = SpringUtil.getBean(ISysDeptService.class);
        SysDept dept = deptService.selectDeptById(Long.parseLong(value));
        return BeanUtil.toBean(dept, JSONObject.class);
    }

    /**
     * 用户绑定解析
     */
    private JSONObject resolveUser(String value) {
        ISysUserService userService = SpringUtil.getBean(ISysUserService.class);
        SysUser user = userService.selectUserById(Long.parseLong(value));
        return BeanUtil.toBean(user, JSONObject.class);
    }
}